package com.smsc.headend.task.engine.service.protocol.imp;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.task.engine.po.PacketTypeDesc;
import com.smsc.headend.task.engine.service.protocol.PacketDecodeService;
import gurux.dlms.GXDLMSTranslator;
import gurux.dlms.TranslatorOutputType;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class DLMSPacketDecodeServiceImpl implements PacketDecodeService {
    @Override
    public PacketTypeDesc getPacketType(String hexPacket, Integer direction) {
        GXDLMSTranslator translator = new GXDLMSTranslator(TranslatorOutputType.SIMPLE_XML);
        PacketTypeDesc typeDesc = new PacketTypeDesc();
        String type = "decodeFail";
        String desc = null;
        try {
            hexPacket = getComparedPacket(hexPacket);
            String xml = translator.messageToXml(ByteUtils.hexStringToByte(hexPacket));
            Pattern pattern = Pattern.compile("<PDU>[\t\r\n.]*<(.*)>");
            Matcher matcher = pattern.matcher(xml);
            if (matcher.find()) {
                type = matcher.group(1);
            }

            desc = getPacketDesc(type, xml);

        } catch (Exception e) {
            //GURUX 4.0.26 bug 解析 ActionRequest会报错, 这里临时判断
            byte[] pdu;
            try {
                pdu = translator.getPdu(ByteUtils.hexStringToByte(hexPacket));
                if((pdu[0] & 0xff) == 0xc3) {
                    type = "ActionRequest";
                    desc = "Success";
                }
                else {
                    log.error("request_packet: decode failed {}", hexPacket, e);
                }
            } catch (Exception ex) {
                log.error("request_packet: decode failed {}", hexPacket, e);
            }
        }

        typeDesc.setType(type);
        typeDesc.setDesc(desc);
        return typeDesc;
    }

    /**
     * 比较PDU size 不对的话把size替换为正确的
     * @param hexPacket
     * @return
     */
    private String getComparedPacket(String hexPacket) {
        hexPacket = hexPacket.replaceAll(" +", "");
        if (hexPacket.length() < 16) {
            return hexPacket;
        }
        if(hexPacket.startsWith("7E")) {
            // 46报文目前pduSize都是正确的不需要修改
            return hexPacket;
        }
        int pduSize = Integer.parseInt(hexPacket.substring(12,16), 16);
        int realPduSize = (hexPacket.length() - 16) / 2;
        if (pduSize != realPduSize) {
            StringBuilder sb = new StringBuilder();
            sb.append(hexPacket);
            sb.replace(12, 16, String.format("%04X", realPduSize));
            return sb.toString();
        }
        return hexPacket;
    }

    private String getPacketDesc(String type, String xml) {
        if ("ExceptionResponse".equalsIgnoreCase(type)) {
            Pattern pattern = Pattern.compile("<StateError Value=\"(.*)\"");
            Matcher matcher = pattern.matcher(xml);
            if (matcher.find()) {
                return matcher.group(1);
            }
        } else if ("ActionResponse".equalsIgnoreCase(type)) {
            Pattern pattern = Pattern.compile("<Result Value=\"(.*)\"");
            Matcher matcher = pattern.matcher(xml);
            if (matcher.find()) {
                return matcher.group(1);
            }
        } else if ("GetResponse".equalsIgnoreCase(type)){
            Pattern pattern = Pattern.compile("<DataAccessError Value=\"(.*)\"");
            Matcher matcher = pattern.matcher(xml);
            if (matcher.find()) {
                return matcher.group(1);
            } else {
                return "Success";
            }
        } else if ("SetResponse".equalsIgnoreCase(type)){
            Pattern pattern = Pattern.compile("<Result Value=\"(.*)\"");
            Matcher matcher = pattern.matcher(xml);
            if (matcher.find()) {
                return matcher.group(1);
            } else {
                return "Success";
            }
        } else {
            return "Success";
        }
        return null;
    }

}
